﻿using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace MessageHandler
{
	public class Serializer
	{
		XmlSerializer xmlSer;
		XmlReaderSettings readerSettings = new XmlReaderSettings();

		public Serializer(Type type)
		{
			try
			{
				xmlSer = new XmlSerializer(type);
				readerSettings.ValidationType = ValidationType.Schema;
				readerSettings.Schemas.Add(null, @"message.xsd");
				readerSettings.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(readerSettings_ValidationEventHandler);
			}
			catch
			{
				throw new ChatException("Objekt kann nicht serialisiert werden");
			}
		}

		#region Serialize

		public void SerializeObject(object obj, ref MemoryStream stream)
		{
			try
			{
				XmlWriterSettings settings = new XmlWriterSettings();
				settings.Encoding = Encoding.UTF8;
				XmlWriter writer = XmlWriter.Create(stream, settings);
				SerializeObject(obj, writer);
			}
			catch
			{
				throw new ChatException("Serialisieren nicht möglich");
			}
			finally
			{
				stream.Close();
			}
		}

		public void SerializeObject(object obj, XmlWriter xmlWriter)
		{
			try
			{
				xmlSer.Serialize(xmlWriter, obj);
			}
			catch
			{
				throw new ChatException("Serialisieren nicht möglich");
			}
			finally
			{
				xmlWriter.Close();
			}
		}

		#endregion

		#region Deserialize

		public object DeserializeObject(MemoryStream stream)
		{
			try
			{
				byte[] bytesAll = stream.ToArray();
				Validate(XmlReader.Create(new MemoryStream(bytesAll), readerSettings));
				if (!hasErrors)
				{
					return DeserializeObject(XmlReader.Create(new MemoryStream(bytesAll), readerSettings));
				}

				throw new ChatException("Deserialisieren nicht möglich");
			}
			catch (Exception err)
			{
				throw err;
			}
			finally
			{
				stream.Close();
			}
		}

		private void Validate(XmlReader reader)
		{
			try
			{
				while (reader.Read()) { }
			}
			catch
			{
				throw new ChatException("Validieren nicht möglich");
			}
		}

		private bool hasErrors = false;

		void readerSettings_ValidationEventHandler(object sender, System.Xml.Schema.ValidationEventArgs e)
		{
			if (e.Severity == System.Xml.Schema.XmlSeverityType.Error)
			{
				hasErrors = true;
			}
		}

		public object DeserializeObject(XmlReader xmlReader)
		{
			try
			{
				return xmlSer.Deserialize(xmlReader);
			}
			catch
			{
				throw new ChatException("Deserialisieren nicht möglich");
			}
			finally
			{
				xmlReader.Close();
			}
		}

		#endregion
	}
}
